package io.hellsinger.vortex.ui.component.item.field

import android.animation.ValueAnimator
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RectShape
import android.os.Build
import android.text.Editable
import android.text.TextUtils
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout.LayoutParams.WRAP_CONTENT
import android.widget.TextView
import io.hellsinger.vortex.ui.component.dp
import io.hellsinger.vortex.ui.component.updatePadding
import kotlin.math.roundToInt

class TextFieldItemView(
    context: Context,
) : FrameLayout(context),
    View.OnFocusChangeListener {
    var error: String = ""

    private var isFocused = false
        set(value) {
            if (field != value) {
                field = value
                ensureViewState()
            }
        }

    private val animator =
        ValueAnimator.ofFloat(0F, 1F).apply {
            interpolator = DecelerateInterpolator(1.76F)
            duration = 150L

            addUpdateListener { animator ->
                onFactor(animator.animatedFraction)
            }
        }

    private val cursor =
        ShapeDrawable(RectShape()).apply {
            intrinsicHeight = 2F.dp.roundToInt()
            intrinsicWidth = 2F.dp.roundToInt()
        }

    private val field =
        EditText(context).apply {
            layoutParams =
                LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
                    topMargin = 20.dp
                }
            imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
            gravity = Gravity.CENTER_VERTICAL or Gravity.LEFT
            setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17f)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                textCursorDrawable = cursor
            }
            updatePadding(
                2.dp,
                8.dp,
                2.dp,
                10.dp,
            )
        }
    private val hintView =
        TextView(context).apply {
            ellipsize = TextUtils.TruncateAt.END
            pivotY = 0F
            pivotX = 0F
            gravity = Gravity.CENTER_VERTICAL or Gravity.START
            isSingleLine = true
            text = "Hint"
            layoutParams =
                LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
                    topMargin = 20.dp
                }
            setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17F)
            updatePadding(left = 2.dp, right = 2.dp)
        }

    var text: String
        get() = this.field.text.toString()
        set(value) = this.field.setText(value)

    var hint: CharSequence
        get() = this.hintView.text
        set(value) {
            this.hintView.text = value
        }

    init {
        addView(field)
        addView(hintView)

        field.onFocusChangeListener = this
    }

    fun addTextWatcher(watcher: TextWatcher) {
        field.addTextChangedListener(
            object : android.text.TextWatcher {
                override fun afterTextChanged(sequence: Editable) =
                    watcher.afterTextChanged(
                        this@TextFieldItemView,
                        sequence,
                    )

                override fun beforeTextChanged(
                    sequence: CharSequence,
                    start: Int,
                    count: Int,
                    after: Int,
                ) = watcher.beforeTextChanged(
                    this@TextFieldItemView,
                    sequence,
                    start,
                    count,
                    after,
                )

                override fun onTextChanged(
                    sequence: CharSequence,
                    start: Int,
                    before: Int,
                    count: Int,
                ) = watcher.onTextChanged(
                    this@TextFieldItemView,
                    sequence,
                    start,
                    before,
                    count,
                )
            },
        )
    }

    fun setHintTextColor(color: Int) {
        hintView.setTextColor(color)
    }

    fun setFieldTextColor(color: Int) {
        field.setTextColor(color)
    }

    fun setFieldLineColor(color: Int) {
        field.backgroundTintList = ColorStateList.valueOf(color)
    }

    fun setFieldCursorColor(color: Int) {
        cursor.paint.color = color
    }

    override fun onFocusChange(
        v: View,
        hasFocus: Boolean,
    ) {
        isFocused = hasFocus
    }

    private fun onFactor(factor: Float) {
        val focusedFactor = if (isFocused) factor else 1F - factor
        val scale = 1F - (0.2F * focusedFactor)
        hintView.scaleX = scale
        hintView.scaleY = scale
        hintView.translationY = (-20F).dp * scale
    }

    private fun ensureViewState() {
        animator.start()
    }

    interface TextWatcher {
        fun afterTextChanged(
            view: TextFieldItemView,
            sequence: Editable,
        )

        fun beforeTextChanged(
            view: TextFieldItemView,
            sequence: CharSequence,
            start: Int,
            count: Int,
            after: Int,
        )

        fun onTextChanged(
            view: TextFieldItemView,
            sequence: CharSequence,
            start: Int,
            before: Int,
            count: Int,
        )
    }
}
